package core

import (
	"context"
	gokitendpoint "github.com/go-kit/kit/endpoint"
	"sort"
)

type EndpointMaker interface {
	Name() string
	Request() interface{}
	Response() interface{}
	Middlewares() []gokitendpoint.Middleware
	Endpoint(mws ...gokitendpoint.Middleware) gokitendpoint.Endpoint
	RegisterMiddlewares(mws ...gokitendpoint.Middleware)
	GenerateHttpTransport() HttpTransportI
	GenerateNatsMicroTransport() NatsMicroTransportI
}

type EndpointNode[REQ, RESP any] struct {
	middlewares  []gokitendpoint.Middleware
	EndpointName string
	ServiceFunc  func(context.Context, REQ) (RESP, error)
}

func RegisterEndpointNode[REQ, RESP any](ec EndpointCollector, endpointName string, serviceFunc func(context.Context, REQ) (RESP, error), middlewares ...gokitendpoint.Middleware) {
	ep := EndpointNode[REQ, RESP]{EndpointName: endpointName, ServiceFunc: serviceFunc}
	ec.SetEndpointNode(endpointName, &ep)
}

//func (e *EndpointNode[REQ, RESP]) GenerateNatsTransport() NatsTransportI {
//	return &NatsTransport[REQ, RESP]{
//		EndpointName: e.EndpointName,
//	}
//}

func (e *EndpointNode[REQ, RESP]) GenerateNatsMicroTransport() NatsMicroTransportI {
	return &NatsMicroTransport[REQ, RESP]{
		EndpointName: e.EndpointName,
	}
}

func (e *EndpointNode[REQ, RESP]) GenerateHttpTransport() HttpTransportI {
	return &HttpTransport[REQ, RESP]{
		EndpointName: e.EndpointName,
	}
}

func (e *EndpointNode[REQ, RESP]) Middlewares() []gokitendpoint.Middleware {
	return e.middlewares
}

func (e *EndpointNode[REQ, RESP]) RegisterMiddlewares(mws ...gokitendpoint.Middleware) {
	for _, md := range mws {
		e.middlewares = append(e.middlewares, md)
	}

}

func (e *EndpointNode[REQ, RESP]) Name() string {
	return e.EndpointName
}

func (e *EndpointNode[REQ, RESP]) Request() interface{} {
	var r = new(REQ)
	return r
}

func (e *EndpointNode[REQ, RESP]) Response() interface{} {
	var r = new(RESP)
	return r
}

func (e *EndpointNode[REQ, RESP]) Endpoint(mws ...gokitendpoint.Middleware) gokitendpoint.Endpoint {

	// make endpoint func
	svc := func(ctx context.Context, request interface{}) (interface{}, error) {
		req := request.(REQ)
		v, err := e.ServiceFunc(ctx, req)
		if err != nil {
			return v, err
		}
		return v, nil
	}

	// register middlewares
	e.RegisterMiddlewares(mws...)

	// wrap endpoint func with middlewares
	var mwsList = make([]gokitendpoint.Middleware, len(e.middlewares))

	// 使用for循环复制数组
	for i := 0; i < len(e.middlewares); i++ {
		mwsList[i] = e.middlewares[i]
	}

	// 倒序处理中间件，先传入的中间件模型装饰在最外层
	sort.SliceStable(mwsList, func(i, j int) bool {
		return true
	})

	for _, mw := range mwsList {
		svc = mw(svc)
	}

	return svc
}

type EndpointCollector interface {
	SetEndpointNode(key string, et EndpointMaker)
	GetEndpointNode(key string) EndpointMaker
	GetEndpointNodesMapper() map[string]EndpointMaker
	Middlewares() []gokitendpoint.Middleware
	RegisterMiddlewares(mws ...gokitendpoint.Middleware)
}

func NewEndpointNodeMapper() EndpointNodeMapper {
	return EndpointNodeMapper{
		mapper: map[string]EndpointMaker{},
	}
}

type EndpointNodeMapper struct {
	mapper      map[string]EndpointMaker
	middlewares []gokitendpoint.Middleware
}

func (e *EndpointNodeMapper) Middlewares() []gokitendpoint.Middleware {
	return e.middlewares
}

func (e *EndpointNodeMapper) SetEndpointNode(key string, et EndpointMaker) {
	et.RegisterMiddlewares(e.middlewares...)
	e.mapper[key] = et
}

func (e *EndpointNodeMapper) GetEndpointNode(key string) EndpointMaker {
	return e.mapper[key]
}

func (e *EndpointNodeMapper) GetEndpointNodesMapper() map[string]EndpointMaker {
	return e.mapper
}

func (e *EndpointNodeMapper) RegisterMiddlewares(mws ...gokitendpoint.Middleware) {
	for _, md := range mws {
		e.middlewares = append(e.middlewares, md)
	}
	for _, et := range e.mapper {
		et.RegisterMiddlewares(mws...)
	}
}
